package com.yjc.manager.holder;

import com.yjc.api.annotation.Api;
import com.yjc.api.annotation.ApiClass;
import com.yjc.manager.classloader.DynaticClassLoader;
import com.yjc.manager.entity.JarInfo;
import com.yjc.manager.scanner.ClassScanner;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 管理加载的class
 *
 * @author 闫佳成
 * @version: 1.0
 * @since 2024/10/8 15:05
 */
public class ClassHolder {
    private final static Logger logger = LoggerFactory.getLogger(ClassHolder.class);

    //key: jarName, value: DynaticClassLoader
    private final Map<String, DynaticClassLoader> jarClassLoaderMap = new ConcurrentHashMap<>();

    //key： jarName, value: map [ key:interfaceClass value:apiClass ]。目前一个jar包里一个接口只能有一个实现类
    private final Map<String,Map<Class<?>,Class<?>>> jarInterfaceMap = new ConcurrentHashMap<>();

    //key: interfaceClass value: jarNameSet
    private final Map<Class<?>,Set<String>> classJarMap = new ConcurrentHashMap<>();

    private static class Instance{
        private static final ClassHolder classHolder = new ClassHolder();
    }

    public static ClassHolder getInstance(){
        return Instance.classHolder;
    }

    /**
     * 根据路径加载jar
     * @param path
     */
    public void loadClass(String path){
        try {
            List<JarInfo> jarInfoList = ClassScanner.findJarInfoListByPath(path);
            if (CollectionUtils.isEmpty(jarInfoList)){return;}
            for (JarInfo jarInfo : jarInfoList) {
                saveClassLoader(jarInfo);
            }
        }catch (Exception e){
            logger.error("load class error: ",e);
        }
        logger.info("加载类完成,{}",path);
    }

    /**
     * 根据文件加载jar
     * @param jarPath
     * @param jarName
     */
    public void loadClassByFile(String jarPath, String jarName){
        try {
            JarInfo jarInfo = ClassScanner.findJarInfoListByFile(jarPath, jarName);
            if (jarInfo == null){return;}
            saveClassLoader(jarInfo);
        }catch (Exception e){
            logger.error("load class error: ",e);
        }
        logger.info("加载类完成,{}:{}",jarPath,jarName);
    }

    public Map<String,Map<Class<?>,Class<?>>> getJarInterfaceMap(){
        return jarInterfaceMap;
    }

    public Map<Class<?>,Set<String>> getClassJarMap(){
        return classJarMap;
    }

    private void saveClassLoader(JarInfo jarInfo){
        DynaticClassLoader classLoader = new DynaticClassLoader(ClassLoader.getSystemClassLoader(), jarInfo.getUrls());
        List<String> classNames = jarInfo.getClassNames();
        if (CollectionUtils.isEmpty(classNames)){return;}
        classNames.forEach(className -> {
            try {
                Class<?> clazz = classLoader.loadClass(className);
                ApiClass apiClass = clazz.getAnnotation(ApiClass.class);
                if(apiClass != null){
                    addToClassJarMap(jarInfo,apiClass);
                    addToJarInterfaceMap(jarInfo,clazz,apiClass);
                }
            } catch (ClassNotFoundException e) {
                logger.warn("class not found: ",e.getMessage());
            }
        });
        //不存在才添加
        jarClassLoaderMap.putIfAbsent(jarInfo.getJarName(), classLoader);
    }

    private synchronized void addToJarInterfaceMap(JarInfo jarInfo,Class<?> clazz,ApiClass apiClass) {
        Map<Class<?>, Class<?>> interfaceClassMap = jarInterfaceMap.get(jarInfo.getJarName());
        if (interfaceClassMap == null){
            interfaceClassMap = new HashMap<>();
            jarInterfaceMap.put(jarInfo.getJarName(), interfaceClassMap);
        }
        interfaceClassMap.put(apiClass.interfaceClass(),clazz);
    }

    private synchronized void addToClassJarMap(JarInfo jarInfo,ApiClass apiClass) {
        Set<String> jarNames = classJarMap.get(apiClass.interfaceClass());
        if (jarNames == null){
            jarNames = new HashSet<>();
            classJarMap.put(apiClass.interfaceClass(), jarNames);
        }
        jarNames.add(jarInfo.getJarName());
    }

    /**
     * 卸载加载的类，如果jarName为空就卸载全部
     * @param jarName
     */
    public synchronized void unload(String jarName){
        Iterator<Map.Entry<String, DynaticClassLoader>> iterator = jarClassLoaderMap.entrySet().iterator();
        while (iterator.hasNext()){
            Map.Entry<String, DynaticClassLoader> entry = iterator.next();
            String key = entry.getKey();
            if (StringUtils.isNotBlank(jarName) && !key.equals(jarName)){
                continue;
            }
            unloadJarMap(jarName);
            unloadClassLoader(entry.getValue());
            iterator.remove();
            logger.info("卸载类完成, {}",jarName);
        }
    }

    private void unloadJarMap(String jarName) {
        Map<Class<?>, Class<?>> interfaceClassMap = jarInterfaceMap.get(jarName);
        for (Class<?> interfaceClass : interfaceClassMap.keySet()) {
            Set<String> jarNames = classJarMap.get(interfaceClass);
            jarNames.remove(jarName);
            if (jarNames.isEmpty()){
                classJarMap.remove(interfaceClass);
            }
        }
        jarInterfaceMap.remove(jarName);
    }

    /**
     * 从类加载器底层的classes中移除连接
     * @param classLoader
     */
    private void unloadClassLoader(DynaticClassLoader classLoader){
        try {
            Field field = ClassLoader.class.getDeclaredField("classes");
            field.setAccessible(true);
            Vector<Class<?>> classes = (Vector<Class<?>>) field.get(classLoader);
            classes.removeAllElements();
            // 卸载类加载器
            classLoader.unload();
        } catch (NoSuchFieldException e) {
           logger.error("动态卸载类，从类加载器中卸载失败",e);
        } catch (IllegalAccessException e) {
            logger.error("动态卸载类，从类加载器中卸载失败",e);
        }
    }
}
